#include <lock_manager/lock_manager.hpp>
#include "efsm.hpp"
#include "efsm_event.hpp"
#include <elog.h>


				
static void thread_event_invoke_handler(void* para)
{
    efsm_arg *block_para = reinterpret_cast<efsm_arg*>(para);

    if(block_para->isblock){ 
        boost::unique_lock<boost::mutex> lock(block_para->mutex);
    }	

    EFSM_EVENT_HANDLER handler = NULL;
    handler = EFSM_HANDLER(main_set, block_para->event); // 与 EFSM_BIND 相互对应，一个注册信息，一个取出信息
    if(handler){

        //log_w(" ***  block_para->in_arg = %d  \n", (int)(block_para->in_arg));  
        handler(block_para->event, block_para->in_arg);
    }

    // 检测事件发送方是否处于阻塞状态，isblock是阻塞标志
    if(block_para->isblock){                  
       block_para->cond.notify_all();
    }	
}


/** 例如主线程调用一个注册命令，那么注册的结果就需要返回给主线程，所以主线程必须要等待到注册过程结束后才去读参数 **/
void event_invoke_block1(EFSM_EVENT_TYPE event,  void *arg)
{
    efsm_arg block_para;
    block_para.in_arg  = arg;
    block_para.isblock = true;
    block_para.event   = event;

    /***
     * 这里需要新开一个线程，要使用锁的生产者和消费者应分布在不同的线程内， 否则，在一个线程内，会造成死锁 *
     ***/
    boost::thread t_thread_event_invoke_report(thread_event_invoke_handler,  &block_para);
    t_thread_event_invoke_report.detach();

    boost::unique_lock<boost::mutex> lock(block_para.mutex);      
    block_para.cond.wait(lock); 
    log_w("event_invoke_block1(blocked, waiting new thread to notify) ... done.\n");
}



// 这里直接回调，相当于也是阻塞的，但是上面的版本，使用了条件变量，代码的表达力更加突出
void event_invoke_block2(EFSM_EVENT_TYPE event,  void *arg)
{
    efsm_arg block_para;
    block_para.isblock = false;
    block_para.in_arg = arg;

    EFSM_EVENT_HANDLER handler = NULL;
    handler = EFSM_HANDLER(main_set, event); // 与 EFSM_BIND 相互对应，一个注册信息，一个取出信息
    if(handler)
        handler(event, &block_para);
        
    log_w("event_invoke_block(blocked, waiting the event to be done here) ... done.\n");
}



void event_invoke_nonblock(EFSM_EVENT_TYPE event,  void *arg)
{
    efsm_arg block_para;
    block_para.in_arg  = arg;
    block_para.isblock = false;
    block_para.event   = event;

    boost::thread t_thread_event_invoke_report(thread_event_invoke_handler,  &block_para);
    t_thread_event_invoke_report.detach();
 
    log_w("event_invoke_nonblock(blocked, do not need to wait the event deal) ...\n");
}



